using System;
using System.Collections.Generic;

public class IntMapper : GenMapper<int>{
	class ConditionGT : Condition<int>{
		int start;
		public ConditionGT (int start)
		{
			this.start = start;
		}
		public override bool match (int from)
		{
			return from > start;
		}
		public override string ToString ()
		{
			return string.Format ("[ConditionGT start={0}]",start);
		}

		
	}
	class ConstRule : Rule<int>{
		int val;
		public ConstRule (int val)
		{
			this.val = val;
		}

		public override int map (int from){
			return val;
		}
		public override string ToString ()
		{
			return string.Format ("[ConstRule val={0}]",val);
		}
		
	}
	class ConstStrategy : Strategy<int>{
		public override Rule<int> toRule(IList<Pair<int>> pairs){
			Dictionary<int,int> counts = new Dictionary<int, int>();
			foreach(Pair<int> p in pairs){
				if( !counts.ContainsKey(p.to) ){
				  counts[p.to]=1;
				}else{
				  counts[p.to]++;
			      return new ConstRule(p.to);
				}
			}
			return null;
		}
	}

	class ConstPlusXRule : Rule<int>{
		int val;
		public ConstPlusXRule (int val)
		{
			this.val = val;
		}

		public override int map (int from){
			return from + val;
		}
		public override string ToString ()
		{
			return string.Format ("[Rule x+{0}]",val);
		}
		
	}
	class ConstPlusXStrategy : Strategy<int>{
		public override Rule<int> toRule(IList<Pair<int>> pairs){
			Dictionary<int,int> counts = new Dictionary<int, int>();
			foreach(Pair<int> p in pairs){
				int pdiff = p.to - p.from;
				if( !counts.ContainsKey(pdiff) ){
				  counts[pdiff]=1;
				}else{
				  counts[pdiff]++;
			      return new ConstPlusXRule(pdiff);
				}
			}
			return null;
		}
	}

	
	
	public IntMapper(){
  	// y = a*x + b
		strategies.Add(new ConstStrategy());
		strategies.Add(new ConstPlusXStrategy());
		Console.WriteLine("---- new IntMapper ----");
	}
	

	protected override void ruleCompose (Rule<int> newRule)
	{
		int oldMax = maxCurrRuleOk();
    	int countGoodOver=0;
    	foreach(Pair<int> p in unbound){
    		if( p.from > oldMax && newRule.map(p.from) == p.to ){
    			countGoodOver++;
    		}
    	}
    	if( countGoodOver >= 2 ){
    		newRule.ChainedRule = rule;
    		newRule.Condition = new ConditionGT(oldMax);
    		rule = newRule; // composite rule
    		Console.WriteLine("adding chained rule "+newRule+" condition "+newRule.Condition
    			+" oldMax="+oldMax+" countGoodOver="+countGoodOver);
    	}else{
    		Console.WriteLine("skipped conflicting rule "+newRule);
    	}
	}
	
	int maxCurrRuleOk(){
		bool first=true;
		int max=0;
		foreach(int k in all.Keys){
			if( rule.mapChained(k)==all[k] ){
				if( first ){
					first=false;
					max=k;
				}else if( k>max ){
					max = k;
				}
			}
		}
		return max;
	}
	

	
}

